#ifndef AVALON_BUFFER_HPP
#define AVALON_BUFFER_HPP
#include <boost/shared_array.hpp>
#include "Avalon/IO/IO.hpp"

namespace Avalon {
namespace IO {

  /*! \class Buffer
   *  \brief Manages a pointer to raw data.
   *  \author Kamal Mansouri <kranar@hotmail.com>
   */
  class Buffer {
    public:

      //! Constructs a Buffer.
      Buffer();

      //! Constructs a Buffer with a pre-allocated initial size.
      /*!
        \param initialSize The initial size to pre-allocate.
      */
      Buffer(int initialSize);

      //! Constructs a Buffer by copying existing data.
      /*!
        \param data The unmanaged data to copy.
        \param size The size of the data to copy.
      */
      Buffer(const void* data, int size);

      //! Copies a Buffer.
      /*!
        \param buffer The Buffer to copy.
      */
      Buffer(const Buffer& buffer);

      ~Buffer();

      //! Assigns a Buffer to this.
      /*!
        \param rhs The Buffer to assign to this.
      */
      Buffer& operator =(const Buffer& rhs);

      //! Returns <code>true</code> iff GetSize() == 0.
      bool IsEmpty() const;

      //! Grows this Buffer.
      /*!
        \param size The additional size to grow this Buffer by.
      */
      void Grow(int size);

      //! Shrinks this Buffer.
      /*!
        \param size The size to shrink the Buffer to.
      */
      void Shrink(int size);

      //! Ensures this Buffer has a certain amount of space.
      /*!
        \param size The total amount of space that needs to be reserved.
      */
      void Reserve(int size);

      //! Writes to this Buffer.
      /*!
        \param index The index to begin writing to.
        \param source The source to write from.
        \param size The size to write.
      */
      void Write(int index, const void* source, int size);

      //! Appends a Buffer.
      /*!
        \param buffer The Buffer to append.
      */
      void Append(const Buffer& buffer);

      //! Appends raw data.
      /*!
        \param data The data to append.
        \param size The size of the data to append.
      */
      void Append(const void* data, int size);

      //! Swaps the contents of this Buffer with another.
      /*!
        \param buffer The Buffer to swap with.
      */
      void Swap(Buffer& buffer);

      //! Resets this Buffer.
      void Reset();

      //! Returns the raw data for read-only access.
      const char* GetData() const;

      //! Returns the raw data for read/write access.
      char* GetMutableData();

      //! Returns the size, in bytes, of the data.
      int GetSize() const;

    private:
      int m_size;
      int m_availableSize;
      boost::shared_array<char> m_data;

      Buffer(const boost::shared_array<char>& data, int size,
        int availableSize);
  };

  //! Swaps two Buffers.
  /*!
    \param a One of the Buffer's to swap.
    \param b The Buffer to swap with.
  */
  void swap(Buffer& a, Buffer& b);
}
}

namespace std {
  template<> void swap(Avalon::IO::Buffer& a, Avalon::IO::Buffer& b);
}

#endif // AVALON_BUFFER_HPP
